[Android] surfaceView中VelocityTable速率盘

surfaceView系列02

Posted by Aerber Zhou on 2017-04-25

一.大体

一些和VJ中差不多作用或者用法的就不再细说了

变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//设置表盘的最大值
public double valueMax = 100;

private Thread thread;

private SurfaceHolder holder;

private Paint paint;

//@param shader : 用于绘制渐变色
//从左向右依次为绿色,黄色,红色的渐变色
private Shader shader;

//align用于
private Align align;

//绘制表盘的区域
private RectF region;

//瞬时数据
private double value = 0;

方法:

基本和VJ中差不多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//三个构造函数
public VelocityTable(Context c){ }

public VelocityTable(Context c, AttributeSet attrs) { }

//和第二个构造函数一样,因为不懂int defStyleAttr的使用方法
public VelocityTable(Context context, AttributeSet attrs, int defStyleAttr) {}

//初始化,和VirtualJokstick中的init一个作用
private void init() {}

//测量控件的大小
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { }


//绘制函数
private void mDraw() { }

//添加数据函数
public void setValue(double newValue) { }

//枚举tag类型
private enum Align {
left, center, right;
}

二.构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//三种构造函数
public VelocityTable(Context c) {
super(c);
//在layout中tag无特殊说明,则渐变色默认从左往右
align = Align.left;
init();
}

public VelocityTable(Context c, AttributeSet attrs) {
super(c, attrs);

//通过tag来判断控件一开始的起始渐变色的位置
//获取tag的文字
String sAlign = (String) getTag();
//默认设置为从左往右
align = Align.left;
//从中间开始
if (sAlign.equals("center"))
align = Align.center;
//从右往左
if (sAlign.equals("right"))
align = Align.right;

init();
}

//和第二个构造函数一样,因为不懂int defStyleAttr的使用方法
public VelocityTable(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
String sAlign = (String) getTag();
align = Align.left;
if (sAlign.equals("center"))
align = Align.center;
if (sAlign.equals("right"))
align = Align.right;
init();
}

三.private void init() {}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//初始化,和VirtualJokstick中的init差不多
private void init() {
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
//设置文字对齐方式为居中对齐
paint.setTextAlign(Paint.Align.CENTER);
//设置文字大小
paint.setTextSize(25);

//@param region : velocityTable的矩形区域
region = new RectF();

holder = this.getHolder();
holder.addCallback(new SurfaceHolder.Callback() {

public void surfaceCreated(SurfaceHolder holder) {
thread = new Thread(new Runnable() {

public void run() {
while (true) {
try {
mDraw();
Thread.sleep(50);
} catch (InterruptedException e) {

}
}
}
});
thread.start();
}

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

public void surfaceDestroyed(SurfaceHolder holder) {
thread.interrupt();
thread = null;
}
});
}

四.protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override
//测量控件的大小
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//设置表盘的半圆半径
//由于我们在layout文件中给VT组件分配的区域为矩形,而在画半圆的时候canvas实际占用的为一个圆范围,所以需要把layout中给VT分配的高变两倍。
int radius = Math.min(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec) * 2) / 2;
region.set(0, 0, radius * 2, radius * 2);
switch (align) {
case left:
//tag = left时
//从左向右依次为绿色,黄色,红色,分别在0.5,0.8出产生渐变色
//这里解释一下0.5,0.8,绘制颜色渲染圆时,是绘制一整个圆,和绘制半圆是一样的,但是我们只需要一个半圆的渐变色
//0.5指的是从水平右边为0,顺时针经过0.5个圆后开始绘制绿色,然后在0.75的圆后开始绘制黄色,到1时为红色
//这样达到绘制渐变色的方式
shader = new SweepGradient(getWidth() / 2, getHeight(), new int[]{Color.GREEN, Color.YELLOW, Color.RED}, new float[]{0.5f, 0.8f, 1f});
break;
case center:
//tag = center时
//从中间向两边颜色对称,但是绘制的时候还是要从左往右绘制,所以颜色依次为红色,黄色,绿色,黄色,红色
//分布在0.5,0.55,0.75,0.95,1
//红色在边缘占0.05个圆,黄色占0.2个圆,绿色占0.2个圆
shader = new SweepGradient(getWidth() / 2, getHeight(), new int[]{Color.RED, Color.YELLOW, Color.GREEN, Color.YELLOW, Color.RED}, new float[]{0.5f, 0.55f, 0.75f, 0.95f, 1f});
break;
case right:
//tag = right 时
//和tag = left 相反
shader = new SweepGradient(getWidth() / 2, getHeight(), new int[]{Color.GREEN, Color.YELLOW, Color.RED}, new float[]{1f, 0.7f, 0.5f});
break;
}
setMeasuredDimension(radius * 2, radius);
}

五.private void mDraw() {}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

//绘制函数
private void mDraw() {
Canvas c = null;
try {
c = holder.lockCanvas();
if (c == null) return;

c.drawColor(Color.WHITE);
//设置透明度 此处为半透明
//绘制半圆
paint.setAlpha(128);
paint.setColor(getResources().getColor(R.color.circle_inner_color));
c.drawArc(region, -180, 180, true, paint);

//draw arc
{
paint.setShader(shader);
//全透明
paint.setAlpha(255);
//画半圆的起始点不同由tag决定
switch (align) {
case left:
c.drawArc(region, -180, (float) (180f * value / valueMax), true, paint);
break;
case center:
c.drawArc(region, 270, (float) (90f * value / valueMax), true, paint);
break;
case right:
c.drawArc(region, 0, (float) (-180f * value / valueMax), true, paint);
break;
}
paint.setShader(null);
paint.setAlpha(128);
}
//draw line
{
//velocityTable的指针和圆心颜色
paint.setColor(getResources().getColor(R.color.circle_progress_point));
paint.setAlpha(255);
c.save();
//默认绘制为屏幕左上角,我们需要平移到半圆圆心
//关于translate等画布操作请看surfaceview中的第二章
c.translate(region.centerX(), region.centerY());
//绘制圆心
c.drawCircle(0, 0, 10, paint);
switch (align) {
case left:
c.rotate((float) (180f * value / valueMax + 90));
break;
case center:
c.rotate((float) (90f * value / valueMax + 180));
break;
case right:
c.rotate((float) (-180f * value / valueMax - 90));
break;
}

//绘制三角形的path范围
Path p = new Path();
//设三角形指针起点为(-10,0),设置为负是因为后面会把这个等腰三角形的底边的中心和圆心相重合
p.moveTo(-10, 0);
//三个lineto函数,相当于按顺时针画出三角形的轮廓
p.lineTo(10, 0);
p.lineTo(0, getHeight());
p.lineTo(-10, 0);

//填充三角形内部颜色
c.drawPath(p, paint);

c.restore();
paint.setAlpha(128);
}
//draw text
//绘制显示的数据
//白底黑字
{
paint.setColor(Color.WHITE);
//取y的绝对值并格式化数据为小数点后两位
String text = String.format("%.2f", Math.abs(value));
//数据显示的范围矩形
Rect bound = new Rect();
//获取字符串的宽度并确定显示数据的矩形大小
paint.getTextBounds(text, 0, text.length(), bound);
//平移此矩形,参数分别为dx,dy
bound.offset(-bound.width() / 2, 0);
c.save();
c.translate(getWidth() / 2, getHeight() - 20);
c.drawRect(bound, paint);

paint.setColor(Color.BLACK);
c.drawText(text, 0, 0, paint);
c.restore();
}
} catch (Exception e) {

} finally {
if (c != null)
holder.unlockCanvasAndPost(c);
}

}

六.public void setValue(double newValue) {}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//添加数据函数
public void setValue(double newValue) {
if (align == Align.center)
//三元运算符
//改写成这样比较好理解,但是代码就不简洁了

//if (value > valueMax) value = valueMax;
//else if (value < -valueMax) value = -valueMax;
//else value = newValue;

value = newValue > valueMax ? valueMax : newValue < -valueMax ? -valueMax : newValue;
else
//同理理解
value = newValue > valueMax ? valueMax : newValue < 0 ? 0 : newValue;
}

七.private enum Align {}

1
2
3
4
//枚举tag类型
private enum Align {
left, center, right;
}